package com.isp.org.server.application.facade;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.isp.common.model.exception.APIRuntimeException;
import com.isp.common.model.vo.PageResult;
import com.isp.common.model.vo.Result;
import com.isp.common.utils.PageUtils;
import com.isp.org.api.dto.role.SysRole;
import com.isp.org.server.domain.entity.RoleEntity;
import com.isp.org.server.domain.entity.RoleUserEntity;
import com.isp.org.server.domain.mapper.RoleUserMapper;
import com.isp.org.server.domain.service.RoleService;
import com.isp.org.server.domain.service.RoleUserService;
import com.isp.org.server.interfaces.model.ResultCodeEnum;
import com.isp.org.server.interfaces.model.role.mapper.RoleMapStruct;
import com.isp.org.server.interfaces.model.role.vo.BaseRoleVO;
import com.isp.org.server.interfaces.model.role.vo.request.RoleCreateRequest;
import com.isp.org.server.interfaces.model.role.vo.request.RoleUpdateRequest;
import com.isp.org.server.interfaces.model.role.vo.response.RoleInfoResponse;
import com.isp.org.server.interfaces.model.role.vo.response.RoleUserResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author linsy
 * @version 1.0
 * @created 2024/3/13 10:19
 */
@Service
@RequiredArgsConstructor
public class RoleFacade {

    private final RoleService roleService;
    private final RoleUserService roleUserService;

    public PageResult<RoleInfoResponse> pageList(int pageNum, int pageSize) {
        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        List<RoleEntity> roleEntityList = roleService.findByApp(null);
        if (CollectionUtils.isEmpty(roleEntityList)) {
            return new PageResult<>();
        }
        List<RoleInfoResponse> roleInfoResponses = RoleMapStruct.INSTANCE.entitiesToInfoList(roleEntityList);
        PageInfo<RoleInfoResponse> roleInfoResponsePageInfo = new PageInfo<>(roleInfoResponses);
        return PageResult.build(roleInfoResponsePageInfo.getSize(), roleInfoResponsePageInfo.getPageNum(), page.getTotal(), roleInfoResponses);
    }

    public List<RoleInfoResponse> findAll() {
        List<RoleEntity> roleEntityList = roleService.findByApp(null);
        if (CollectionUtils.isEmpty(roleEntityList)) {
            return Collections.emptyList();
        }
        return RoleMapStruct.INSTANCE.entitiesToInfoList(roleEntityList);
    }

    @Transactional(rollbackFor = Throwable.class)
    public Boolean create(RoleCreateRequest request) {
        this.checkExist(request);
        RoleEntity sysRoleEntity = RoleMapStruct.INSTANCE.createToEntity(request);
        sysRoleEntity.setCreatedAt(new Date());
        sysRoleEntity.setCreatedBy(RoleEntity.DEFAULT_USERNAME);
        sysRoleEntity.setUpdatedAt(new Date());
        return roleService.save(sysRoleEntity);
    }

    @Transactional(rollbackFor = Throwable.class)
    public Boolean update(Long id, RoleUpdateRequest request) {
        RoleEntity oldRoleEntity = roleService.getById(id);
        if (oldRoleEntity == null) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_EXISTS);
        }
        if (!oldRoleEntity.getCode().equals(request.getCode())) {
            this.checkExist(request);
        }
        RoleEntity roleEntity = RoleMapStruct.INSTANCE.updateToEntity(request);
        roleEntity.setId(id);
        roleEntity.setCreatedAt(oldRoleEntity.getCreatedAt());
        roleEntity.setCreatedBy(oldRoleEntity.getCreatedBy());
        roleEntity.setUpdatedAt(new Date());
        roleEntity.setUpdatedBy(RoleEntity.DEFAULT_USERNAME);
        return roleService.save(roleEntity);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void delete(Long id) {
        RoleEntity roleEntity = roleService.getById(id);
        if (roleEntity == null) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
//        if (!roleEntity.getApp().equals(LoginUserThread.get().getApp())) {
//            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
//        }
        roleService.removeById(roleEntity);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void setRoleToUser(Long userId, Set<Long> roleIds) {
        List<RoleEntity> roleEntities = roleService.listByIds(roleIds);
        if (CollectionUtils.isEmpty(roleEntities)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
//        this.checkAdmin(userProfile, roleEntities);
        List<SysRole> roleList = roleUserService.findRolesByUserId(null, userId);
        roleIds = roleIds.stream().filter(e -> !roleList.stream().map(SysRole::getId).collect(Collectors.toList()).contains(e)).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<RoleUserEntity> roleMenu = new ArrayList<>(roleIds.size());
            roleIds.forEach(e -> {
                RoleUserEntity entity = new RoleUserEntity();
                entity.setRoleId(e);
                entity.setUserId(userId);
                entity.setCreator("system");
                entity.setCreatedAt(new Date());
                roleMenu.add(entity);
            });
            roleUserService.saveBatch(roleMenu);
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public void deleteRoleUser(Long userId, Set<Long> roleIds) {
        List<RoleEntity> roleEntities = roleService.listByIds(roleIds);
        if (CollectionUtils.isEmpty(roleEntities)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
//        this.checkAdmin(userProfile, roleEntities);
        roleUserService.deleteInRoleId(userId, roleIds);
    }

    public PageResult<RoleUserResponse> roleUsers(Long id, int pageNum, int pageSize) {
        RoleEntity roleEntity = roleService.findById(null, id);
        if (Objects.isNull(roleEntity)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_NOT_EXIST);
        }
        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        List<RoleUserEntity> roleUserEntityList = roleUserService.queryPage(id);
        if (CollectionUtils.isEmpty(roleUserEntityList)) {
            return new PageResult<>();
        }
        List<RoleUserResponse> responses = RoleMapStruct.INSTANCE.roleUsersToResponses(roleUserEntityList);
        PageInfo<RoleUserResponse> responsePageInfo = new PageInfo<>(responses);
        return PageResult.build(responsePageInfo.getSize(), pageNum, page.getTotal(), responses);
    }

    public <T extends BaseRoleVO> void checkExist(T request) {
        String code = request.getCode();
        RoleEntity roleEntity = roleService.findByCode(request.getApp(), code);
        if (Objects.nonNull(roleEntity)) {
            throw new APIRuntimeException(ResultCodeEnum.ROLE_CODE_EXIST);
        }
    }

}
